﻿////------------------------------------------------------------
//// Game Framework
//// Copyright © 2013-2021 Jiang Yin. All rights reserved.
//// Homepage: https://gameframework.cn/
//// Feedback: mailto:ellan@gameframework.cn
////------------------------------------------------------------


//using GameFramework;
//using GameFramework.Resource;
//using HybridCLR;
//using System.Collections.Generic;
//using System.IO;
//using System.Reflection;
//using System.Threading.Tasks;
//using UnityEngine;
//using UnityGameFramework.Runtime;
//using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;

//namespace Local
//{
//    enum LoadState
//    {
//        None,
//        Idle,
//        LoadAOTAssembly,
//        LoadDLLInfo,
//        LoadDLL,    
//        UnloadDLLInfoAndDLLs,
//        LoadPrefab,
//        LoadError,
//        End,
//    }
//    public class ProcedurePreload : ProcedureBase
//    {
//        HotUpdateProgressForm m_ProgressForm;
//        public override bool UseNativeDialog => false;        

//        LoadAssetCallbacks loadBinaryCallbacks;
//        LoadState loadState = LoadState.None;
//        TextAsset dLLAssetsInfoAsset = null;
//        DLLAssetsInfo dLLAssetsInfo = null;

//        Dictionary<string, TextAsset> dllAssets = new Dictionary<string, TextAsset>();
//        protected override void OnEnter(ProcedureOwner procedureOwner)
//        {
//            base.OnEnter(procedureOwner);
//            m_ProgressForm = MainGameEntry.BuiltinData.GetHotUpdateProgressForm();
//            m_ProgressForm.SetLog("加载...");
//            m_ProgressForm.SetProgress(0);
//            Log.Debug("开始预加载");
//            if(MainGameEntry.Base.EditorResourceMode)
//            {
//                loadState = LoadState.LoadPrefab;
//            }else
//            {
//                loadState = LoadState.LoadAOTAssembly;
//            }

//            dllAssets.Clear();

//            loadBinaryCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetFailureCallback);            
//        }
//        void LoadDLLAssetsInfoAssets(string assetName)
//        {
//            MainGameEntry.Resource.LoadAsset(assetName, typeof(TextAsset), loadBinaryCallbacks, this);
//        }
//        protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
//        {
//            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
//            switch (loadState)
//            {
//                case LoadState.None:
//                    break;
//                case LoadState.Idle:
//                    break;
//                case LoadState.LoadAOTAssembly:
//                    List<Task<string>> tasks = new List<Task<string>>();
//                    foreach(var dll in AOTGenericReferences.PatchedAOTAssemblyList)
//                    {
//                        if(!MainGameEntry.HotUpdate.LoadAOTMetaDllSync)
//                        {
//                            //采用异步加载
//                            tasks.Add(Task.Run<string>(() =>
//                            {
//                                var dllBytes = File.ReadAllBytes($"{Application.streamingAssetsPath}/{dll}");
//                                var err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HomologousImageMode.SuperSet);
//                                return ($"LoadMetadataForAOTAssembly:{dll}. ret:{err}");
//                            }));
//                        }else
//                        {
//                            var dllBytes = File.ReadAllBytes($"{Application.streamingAssetsPath}/{dll}");
//                            var err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HomologousImageMode.SuperSet);
//                            Log.Debug($"LoadMetadataForAOTAssembly:{dll}. ret:{err}");
//                        }
//                    }
//                    foreach (var t in tasks)
//                    {
//                        t.Wait();
//                        Log.Debug(t.Result);
//                    }
//                    Log.Debug($"加载AOT结束");
//                    loadState = LoadState.LoadDLLInfo;
//                    m_ProgressForm.SetProgress(0.3f);
//                    break;
//                case LoadState.LoadDLLInfo:
//                    MainGameEntry.Resource.LoadAsset(MainGameEntry.HotUpdate.DLLAssetsInfoAssetName, typeof(TextAsset), loadBinaryCallbacks, this);
//                    loadState = LoadState.Idle;
//                    break;
//                case LoadState.LoadDLL:
//                    m_ProgressForm.SetProgress(0.6f);
//                    if (dLLAssetsInfo.Names.Count>0)
//                    {
//                        LoadDLLAssetsInfoAssets(dLLAssetsInfo.Names[0]);
//                        loadState = LoadState.Idle;
//                    }else
//                    {
//                        loadState = LoadState.UnloadDLLInfoAndDLLs;
//                    }
//                    break;
//                case LoadState.UnloadDLLInfoAndDLLs:
//                    MainGameEntry.Resource.UnloadAsset(dLLAssetsInfoAsset);
//                    foreach (var name in dllAssets.Keys)
//                    {
//                        MainGameEntry.Resource.UnloadAsset(dllAssets[name]);
//                    }
//                    m_ProgressForm.SetProgress(0.9f);
//                    dllAssets.Clear();
//                    loadState = LoadState.LoadPrefab;
//                    break;
//                case LoadState.LoadPrefab:
//                    MainGameEntry.Resource.LoadAsset(MainGameEntry.HotUpdate.HotUpdateEntryPrefabAssetName, typeof(GameObject), loadBinaryCallbacks, this);
//                    loadState = LoadState.Idle;
//                    break;

//                case LoadState.End:
//                    Log.Debug("加载结束");
//                    m_ProgressForm.SetProgress(1f);
//                    MainGameEntry.BuiltinData.DestroyHotUpdateProgressForm(m_ProgressForm);
//                    loadState = LoadState.Idle;
//                    break;
//                case LoadState.LoadError:
//                    Log.Debug("加载错误");
//                    loadState = LoadState.End;
//                    break;
//            }

//        }
//        void LoadAssetSuccessCallback(string assetName, object asset, float duration, object userData)
//        {
//            Log.Debug($"加载{assetName}成功");
//            if (userData == this)
//            {
//                if(assetName==MainGameEntry.HotUpdate.DLLAssetsInfoAssetName)
//                {
//                    dLLAssetsInfoAsset = asset as TextAsset;
//                    dLLAssetsInfo = Utility.Json.ToObject<DLLAssetsInfo>(dLLAssetsInfoAsset.text);
//                    loadState = LoadState.LoadDLL;                    
//                }else if (assetName == MainGameEntry.HotUpdate.HotUpdateEntryPrefabAssetName)
//                {
//                    GameObject obj = GameObject.Instantiate((GameObject)asset, MainGameEntry.HotUpdate.InstanceRoot.transform);
//                    loadState = LoadState.End;
//                }
//                else
//                {
//                    if(dLLAssetsInfo.Names.Contains(assetName))
//                    {
//                        Assembly.Load(((TextAsset)asset).bytes);
//                        dllAssets.Add(assetName, ((TextAsset)asset));
//                        dLLAssetsInfo.Names.Remove(assetName);
//                        loadState = LoadState.LoadDLL;
//                    }

//                }

//            }
//        }
//        void LoadAssetFailureCallback(string binaryAssetName, LoadResourceStatus status, string errorMessage, object userData)
//        {

//            if (userData == this)
//            {
//                Log.Error(@"导入{0}失败,{1}",binaryAssetName,errorMessage);
//            }
//            loadState = LoadState.LoadError;
//        }
//    }
//}







//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------


using GameFramework;
using GameFramework.Resource;
using HybridCLR;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityGameFramework.Runtime;
using ProcedureOwner = GameFramework.Fsm.IFsm<GameFramework.Procedure.IProcedureManager>;

namespace Local
{
    enum LoadState
    {
        None,
        Idle,
        LoadAOTAssembly,
        LoadDLLInfo,
        LoadDLL,
        UnloadDLLInfoAndDLLs,
        LoadPrefab,
        LoadError,
        End,
    }
    public class ProcedurePreload : ProcedureBase
    {
        HotUpdateProgressForm m_ProgressForm;
        public override bool UseNativeDialog => false;

        LoadAssetCallbacks loadBinaryCallbacks;
        LoadState m_LoadState = LoadState.None;
        TextAsset dLLAssetsInfoAsset = null;
        DLLAssetsInfo m_DLLAssetsInfo = null;

        Dictionary<string, TextAsset> m_DllAssets = new Dictionary<string, TextAsset>();
        protected override void OnEnter(ProcedureOwner procedureOwner)
        {
            base.OnEnter(procedureOwner);
            m_ProgressForm = MainGameEntry.BuiltinData.GetHotUpdateProgressForm();
            m_ProgressForm.SetLog("加载...");
            m_ProgressForm.SetProgress(0);
            Log.Debug("开始预加载");
            if (MainGameEntry.Base.EditorResourceMode)
            {
                m_LoadState = LoadState.LoadPrefab;
            }
            else
            {
                m_LoadState = LoadState.LoadAOTAssembly;
            }

            m_DllAssets.Clear();

            loadBinaryCallbacks = new LoadAssetCallbacks(LoadAssetSuccessCallback, LoadAssetFailureCallback);
        }
        void LoadDLLAssetsInfoAssets(string assetName)
        {
            MainGameEntry.Resource.LoadAsset(assetName, typeof(TextAsset), loadBinaryCallbacks, this);
        }
        int m_DLLsCount = 0;
        float m_LoadedDllsCount = 0;
        protected override void OnUpdate(ProcedureOwner procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
            switch (m_LoadState)
            {
                case LoadState.None:
                    break;
                case LoadState.Idle:
                    break;
                case LoadState.LoadAOTAssembly:
                    //List<Task<string>> tasks = new List<Task<string>>();
                    //foreach(var dll in AOTGenericReferences.PatchedAOTAssemblyList)
                    //{
                    //    if(!MainGameEntry.HotUpdate.LoadAOTMetaDllSync)
                    //    {
                    //        //采用异步加载
                    //        tasks.Add(Task.Run<string>(() =>
                    //        {
                    //            var dllBytes = File.ReadAllBytes($"{Application.streamingAssetsPath}/{dll}");
                    //            var err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HomologousImageMode.SuperSet);
                    //            return ($"LoadMetadataForAOTAssembly:{dll}. ret:{err}");
                    //        }));
                    //    }else
                    //    {
                    //        var dllBytes = File.ReadAllBytes($"{Application.streamingAssetsPath}/{dll}");
                    //        var err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HomologousImageMode.SuperSet);
                    //        Log.Debug($"LoadMetadataForAOTAssembly:{dll}. ret:{err}");
                    //    }
                    //}
                    //foreach (var t in tasks)
                    //{
                    //    t.Wait();
                    //    Log.Debug(t.Result);
                    //}
                    //Log.Debug($"加载AOT结束");
                    m_LoadState = LoadState.LoadDLLInfo;
                    m_ProgressForm.SetProgress(0);
                    break;
                case LoadState.LoadDLLInfo:
                    MainGameEntry.Resource.LoadAsset(MainGameEntry.HotUpdate.DLLAssetsInfoAssetName, typeof(TextAsset), loadBinaryCallbacks, this);
                    m_LoadState = LoadState.Idle;
                    break;
                case LoadState.LoadDLL:                    
                    if (m_DLLAssetsInfo.Enable &&( m_DLLAssetsInfo.Names.Count > 0 || m_DLLAssetsInfo.AOTNames.Count > 0))
                    {
                        //循环加载
                        if (m_DLLAssetsInfo.Names.Count > 0)
                        {
                            LoadDLLAssetsInfoAssets(m_DLLAssetsInfo.Names[0]);
                        }
                        else if (m_DLLAssetsInfo.AOTNames.Count > 0)
                        {
                            LoadDLLAssetsInfoAssets(m_DLLAssetsInfo.AOTNames[0]);
                        }
                        
                        m_LoadState = LoadState.Idle;
                    }
                    else
                    {
                        m_LoadState = LoadState.UnloadDLLInfoAndDLLs;
                    }
                    break;
                case LoadState.UnloadDLLInfoAndDLLs:
                    MainGameEntry.Resource.UnloadAsset(dLLAssetsInfoAsset);
                    foreach (var name in m_DllAssets.Keys)
                    {
                        MainGameEntry.Resource.UnloadAsset(m_DllAssets[name]);
                    }
                    m_DllAssets.Clear();
                    m_LoadState = LoadState.LoadPrefab;
                    break;
                case LoadState.LoadPrefab:
                    m_ProgressForm.SetProgress(0.9f);
                    MainGameEntry.Resource.LoadAsset(MainGameEntry.HotUpdate.HotUpdateEntryPrefabAssetName, typeof(GameObject), loadBinaryCallbacks, this);
                    m_LoadState = LoadState.Idle;
                    break;

                case LoadState.End:
                    Log.Debug("加载结束");
                    m_ProgressForm.SetProgress(1f);
                    MainGameEntry.BuiltinData.DestroyHotUpdateProgressForm(m_ProgressForm);
                    m_LoadState = LoadState.Idle;
                    break;
                case LoadState.LoadError:
                    Log.Debug("加载错误");
                    m_LoadState = LoadState.End;
                    break;
            }

        }
        void LoadAssetSuccessCallback(string assetName, object asset, float duration, object userData)
        {
            Log.Debug($"加载{assetName}成功");
            if (userData == this)
            {
                if (assetName == MainGameEntry.HotUpdate.DLLAssetsInfoAssetName)
                {
                    m_ProgressForm.SetProgress(0.1f);
                    dLLAssetsInfoAsset = asset as TextAsset;
                    m_DLLAssetsInfo = Utility.Json.ToObject<DLLAssetsInfo>(dLLAssetsInfoAsset.text);
                    m_DLLsCount = m_DLLAssetsInfo.Names.Count + m_DLLAssetsInfo.AOTNames.Count;
                    m_LoadedDllsCount = 0;

                    if (m_DLLsCount > 0)
                    {
                        m_LoadState = LoadState.LoadDLL;
                    }
                    else
                    {
                        m_LoadState = LoadState.LoadPrefab;
                    }
                }
                else if (assetName == MainGameEntry.HotUpdate.HotUpdateEntryPrefabAssetName)
                {
                    GameObject obj = GameObject.Instantiate((GameObject)asset, MainGameEntry.HotUpdate.InstanceRoot.transform);
                    m_LoadState = LoadState.End;
                }
                else
                {
                    if (m_DLLAssetsInfo.Names.Contains(assetName))
                    {
                        Assembly.Load(((TextAsset)asset).bytes);
                        m_DllAssets.Add(assetName, ((TextAsset)asset));
                        m_DLLAssetsInfo.Names.Remove(assetName);
                        m_LoadedDllsCount += 1;
                        m_LoadState = LoadState.LoadDLL;
                        m_ProgressForm.SetProgress(0.1f + 0.8f * (m_LoadedDllsCount / m_DLLsCount));
                    }
                    if (m_DLLAssetsInfo.AOTNames.Contains(assetName))
                    {
                        var err = HybridCLR.RuntimeApi.LoadMetadataForAOTAssembly(((TextAsset)asset).bytes, HomologousImageMode.SuperSet);
                        if(err != LoadImageErrorCode.OK)
                        {
                            Log.Error($"LoadMetadataForAOTAssembly:{assetName}. ret:{err}");
                        }
                        m_DllAssets.Add(assetName, ((TextAsset)asset));
                        m_DLLAssetsInfo.AOTNames.Remove(assetName);
                        m_LoadedDllsCount += 1;
                        m_LoadState = LoadState.LoadDLL;
                        m_ProgressForm.SetProgress(0.1f + 0.8f * (m_LoadedDllsCount / m_DLLsCount));
                    }
                }

            }
        }
        void LoadAssetFailureCallback(string binaryAssetName, LoadResourceStatus status, string errorMessage, object userData)
        {

            if (userData == this)
            {
                Log.Error(@"导入{0}失败,{1}", binaryAssetName, errorMessage);
            }
            m_LoadState = LoadState.LoadError;
        }
    }
}
